home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / status.c < prev    next >
C/C++ Source or Header  |  2008-11-07  |  24KB  |  1,058 lines

  1. /*
  2.  * Copyright 1993, 1994, 1995, 1999, 2000 by Paul Mattes.
  3.  *  Permission to use, copy, modify, and distribute this software and its
  4.  *  documentation for any purpose and without fee is hereby granted,
  5.  *  provided that the above copyright notice appear in all copies and that
  6.  *  both that copyright notice and this permission notice appear in
  7.  *  supporting documentation.
  8.  */
  9.  
  10. /*
  11.  *    status.c
  12.  *        This module handles the 3270 status line.
  13.  */
  14.  
  15. #include "globals.h"
  16. #include <X11/StringDefs.h>
  17. #include <X11/Shell.h>
  18. #include "3270ds.h"
  19. #include "appres.h"
  20. #include "screen.h"
  21. #include "cg.h"
  22.  
  23. #include "kybdc.h"
  24. #include "hostc.h"
  25. #include "screenc.h"
  26. #include "statusc.h"
  27. #include "tablesc.h"
  28. #include "utilc.h"
  29.  
  30. extern Window  *screen_window;
  31.  
  32. static XChar2b *status_2b;
  33. static unsigned char *status_1b;
  34. static XChar2b *display_2b;
  35. static Boolean  status_changed = False;
  36.  
  37. static struct status_line {
  38.     Boolean         changed;
  39.     int             start, len, color;
  40.     XChar2b        *s2b;
  41.     unsigned char  *s1b;
  42.     XChar2b        *d2b;
  43. }              *status_line;
  44.  
  45. static int offsets[] = {
  46.     0,    /* connection status */
  47.     8,    /* wait, locked */
  48.     39,    /* shift, insert, timing, cursor position */
  49.     -1
  50. };
  51. #define SSZ ((sizeof(offsets)/sizeof(offsets[0])) - 1)
  52.  
  53. #define CTLR_REGION    0
  54. #define WAIT_REGION    1
  55. #define MISC_REGION    2
  56.  
  57. static int colors[SSZ] =  {
  58.     FA_INT_NORM_NSEL,
  59.     FA_INT_HIGH_SEL,
  60.     FA_INT_NORM_NSEL
  61. };
  62.  
  63. static int colors3279[SSZ] =  {
  64.     COLOR_BLUE,
  65.     COLOR_WHITE,
  66.     COLOR_BLUE
  67. };
  68.  
  69. #define CM    (60 * 10)    /* csec per minute */
  70.  
  71. /*
  72.  * The status line is laid out thusly (M is maxCOLS):
  73.  *
  74.  *   0        "4" in a square
  75.  *   1        "A" underlined
  76.  *   2        solid box if connected, "?" in a box if not
  77.  *   3..7    empty
  78.  *   8...    message area
  79.  *   M-41    Meta indication ("M" or blank)
  80.  *   M-40    Alt indication ("A" or blank)
  81.  *   M-39    Shift indication (Special symbol/"^" or blank)
  82.  *   M-38..M-37    empty
  83.  *   M-36    Compose indication ("C" or blank)
  84.  *   M-35    Compose first character
  85.  *   M-34    empty
  86.  *   M-33    Typeahead indication ("T" or blank)
  87.  *   M-32    empty
  88.  *   M-31    Alternate keymap indication ("K" or blank)
  89.  *   M-30    Reverse input mode indication ("R" or blank)
  90.  *   M-29    Insert mode indication (Special symbol/"I" or blank)
  91.  *   M-28    empty
  92.  *   M-27    Script indication ("S" or blank)
  93.  *   M-26..M-16    empty
  94.  *   M-15..M-9    command timing (Clock symbol and m:ss, or blank)
  95.  *   M-7..M    cursor position (rrr/ccc or blank)
  96.  */
  97.  
  98. /* Positions */
  99.  
  100. #define LBOX    0        /* left-hand box */
  101. #define CNCT    1        /* connection between */
  102. #define RBOX    2        /* right-hand box */
  103.  
  104. #define M0    8        /* message area */
  105.  
  106. #define SHIFT    (maxCOLS-39)    /* shift indication */
  107.  
  108. #define COMPOSE    (maxCOLS-36)    /* compose characters */
  109.  
  110. #define TYPEAHD    (maxCOLS-33)    /* typeahead */
  111.  
  112. #define KMAP    (maxCOLS-31)    /* alt keymap in effect */
  113.  
  114. #define REVERSE (maxCOLS-30)    /* reverse input mode in effect */
  115.  
  116. #define INSERT    (maxCOLS-29)    /* insert mode */
  117.  
  118. #define SCRIPT    (maxCOLS-27)    /* script in progress */
  119.  
  120. #define T0    (maxCOLS-15)    /* timings */
  121. #define    TCNT    7
  122.  
  123. #define C0    (maxCOLS-7)    /* cursor position */
  124. #define CCNT    7
  125.  
  126. #define STATUS_Y    (ROW_TO_Y(maxROWS)+SGAP-1)
  127.  
  128. static unsigned char    nullblank;
  129. static Position        status_y;
  130.  
  131. /* Status line contents (high-level) */
  132.  
  133. static void do_disconnected(void);
  134. static void do_connecting(void);
  135. static void do_nonspecific(void);
  136. static void do_inhibit(void);
  137. static void do_blank(void);
  138. static void do_twait(void);
  139. static void do_syswait(void);
  140. static void do_protected(void);
  141. static void do_numeric(void);
  142. static void do_overflow(void);
  143. static void do_scrolled(void);
  144. static void do_minus(void);
  145.  
  146. static Boolean  oia_undera = True;
  147. static Boolean  oia_boxsolid = False;
  148. static int      oia_shift = 0;
  149. static Boolean  oia_typeahead = False;
  150. static Boolean  oia_compose = False;
  151. static unsigned char oia_compose_char = 0;
  152. static enum keytype oia_compose_keytype = KT_STD;
  153. static enum msg {
  154.     DISCONNECTED,        /* X Not Connected */
  155.     CONNECTING,        /* X Connecting */
  156.     NONSPECIFIC,        /* X */
  157.     INHIBIT,        /* X Inhibit */
  158.     BLANK,            /* (blank) */
  159.     TWAIT,            /* X Wait */
  160.     SYSWAIT,        /* X SYSTEM */
  161.     PROTECTED,        /* X Protected */
  162.     NUMERIC,        /* X Numeric */
  163.     OVERFLOW,        /* X Overflow */
  164.     SCROLLED,        /* X Scrolled */
  165.     MINUS            /* X -f */
  166. }               oia_msg = DISCONNECTED, saved_msg;
  167. static Boolean  msg_is_saved = False;
  168. static int      n_scrolled = 0;
  169. static void     (*msg_proc[])(void) = {
  170.     do_disconnected,
  171.     do_connecting,
  172.     do_nonspecific,
  173.     do_inhibit,
  174.     do_blank,
  175.     do_twait,
  176.     do_syswait,
  177.     do_protected,
  178.     do_numeric,
  179.     do_overflow,
  180.     do_scrolled,
  181.     do_minus
  182. };
  183. static int      msg_color[] = {
  184.     FA_INT_HIGH_SEL,
  185.     FA_INT_NORM_NSEL,
  186.     FA_INT_NORM_NSEL,
  187.     FA_INT_NORM_NSEL,
  188.     FA_INT_NORM_NSEL,
  189.     FA_INT_NORM_NSEL,
  190.     FA_INT_NORM_SEL,
  191.     FA_INT_NORM_SEL,
  192.     FA_INT_NORM_SEL,
  193.     FA_INT_NORM_SEL,
  194.     FA_INT_NORM_SEL,
  195.     FA_INT_NORM_SEL
  196. };
  197. static int      msg_color3279[] = {
  198.     COLOR_WHITE,
  199.     COLOR_WHITE,
  200.     COLOR_WHITE,
  201.     COLOR_WHITE,
  202.     COLOR_BLUE,
  203.     COLOR_WHITE,
  204.     COLOR_WHITE,
  205.     COLOR_RED,
  206.     COLOR_RED,
  207.     COLOR_RED,
  208.     COLOR_WHITE,
  209.     COLOR_RED
  210. };
  211. static Boolean  oia_insert = False;
  212. static Boolean  oia_reverse = False;
  213. static Boolean  oia_kmap = False;
  214. static Boolean    oia_script = False;
  215. static char    *oia_cursor = (char *) 0;
  216. static char    *oia_timing = (char *) 0;
  217.  
  218. static unsigned char disc_pfx[] = {
  219.     CG_lock, CG_space, CG_badcommhi, CG_commjag, CG_commlo, CG_space
  220. };
  221. static unsigned char *disc_msg;
  222. static int      disc_len = sizeof(disc_pfx);
  223.  
  224. static unsigned char cnct_pfx[] = {
  225.     CG_lock, CG_space, CG_commhi, CG_commjag, CG_commlo, CG_space
  226. };
  227. static unsigned char *cnct_msg;
  228. static int      cnct_len = sizeof(cnct_pfx);
  229.  
  230. static unsigned char *a_not_connected;
  231. static unsigned char *a_connecting;
  232. static unsigned char *a_inhibit;
  233. static unsigned char *a_twait;
  234. static unsigned char *a_syswait;
  235. static unsigned char *a_protected;
  236. static unsigned char *a_numeric;
  237. static unsigned char *a_overflow;
  238. static unsigned char *a_scrolled;
  239. static unsigned char *a_minus;
  240.  
  241. static unsigned char *make_amsg(const char *key);
  242. static unsigned char *make_emsg(unsigned char prefix[], const char *key,
  243.     int *len);
  244.  
  245. static void status_render(int region);
  246. static void do_ctlr(void);
  247. static void do_msg(enum msg t);
  248. static void paint_msg(enum msg t);
  249. static void do_insert(Boolean on);
  250. static void do_reverse(Boolean on);
  251. static void do_kmap(Boolean on);
  252. static void do_script(Boolean on);
  253. static void do_shift(int state);
  254. static void do_typeahead(int state);
  255. static void do_compose(Boolean on, unsigned char c, enum keytype keytype);
  256. static void do_timing(char *buf);
  257. static void do_cursor(char *buf);
  258.  
  259. static void status_connect(Boolean connected);
  260. static void status_3270_mode(Boolean connected);
  261. static void status_half_connect(Boolean ignored);
  262.  
  263.  
  264. /* Initialize the status line */
  265. void
  266. status_init(void)
  267. {
  268.     a_not_connected = make_amsg("statusNotConnected");
  269.     disc_msg = make_emsg(disc_pfx, "statusNotConnected",
  270.         &disc_len);
  271.     a_connecting = make_amsg("statusConnecting");
  272.     cnct_msg = make_emsg(cnct_pfx, "statusConnecting", &cnct_len);
  273.     a_inhibit = make_amsg("statusInhibit");
  274.     a_twait = make_amsg("statusTwait");
  275.     a_syswait = make_amsg("statusSyswait");
  276.     a_protected = make_amsg("statusProtected");
  277.     a_numeric = make_amsg("statusNumeric");
  278.     a_overflow = make_amsg("statusOverflow");
  279.     a_scrolled = make_amsg("statusScrolled");
  280.     a_minus = make_amsg("statusMinus");
  281.  
  282.     register_schange(ST_HALF_CONNECT, status_half_connect);
  283.     register_schange(ST_CONNECT, status_connect);
  284.     register_schange(ST_3270_MODE, status_3270_mode);
  285. }
  286.  
  287. /* Reinitialize the status line */
  288. void
  289. status_reinit(unsigned cmask)
  290. {
  291.     unsigned i;
  292.  
  293.     if (cmask & FONT_CHANGE)
  294.         nullblank = *standard_font ? ' ' : CG_space;
  295.     if (cmask & (FONT_CHANGE | MODEL_CHANGE)) {
  296.         status_y = STATUS_Y;
  297.         if (!*descent)
  298.             ++status_y;
  299.     }
  300.     if (cmask & MODEL_CHANGE) {
  301.         if (status_line)
  302.             XtFree((char *)status_line);
  303.         status_line = (struct status_line *)XtCalloc(sizeof(struct status_line), SSZ);
  304.         if (status_2b != (XChar2b *)NULL)
  305.             XtFree((char *)status_2b);
  306.         status_2b = (XChar2b *)XtCalloc(sizeof(XChar2b), maxCOLS);
  307.         if (status_1b != (unsigned char *)NULL)
  308.             XtFree((char *)status_1b);
  309.         status_1b = (unsigned char *)XtCalloc(sizeof(unsigned char),
  310.             maxCOLS);
  311.         if (display_2b != (XChar2b *)NULL)
  312.             XtFree((XtPointer)display_2b);
  313.         display_2b = (XChar2b *)XtCalloc(sizeof(XChar2b), maxCOLS);
  314.         offsets[SSZ] = maxCOLS;
  315.         if (appres.mono)
  316.             colors[1] = FA_INT_NORM_NSEL;
  317.         for (i = 0; i < SSZ; i++) {
  318.             status_line[i].start = offsets[i];
  319.             status_line[i].len = offsets[i+1] - offsets[i];
  320.             status_line[i].s2b = status_2b + offsets[i];
  321.             status_line[i].s1b = status_1b + offsets[i];
  322.             status_line[i].d2b = display_2b + offsets[i];
  323.         }
  324.     } else
  325.         (void) memset(display_2b, 0, maxCOLS * sizeof(XChar2b));
  326.     if (cmask & (COLOR_CHANGE | MODEL_CHANGE)) {
  327.         for (i = 0; i < SSZ; i++) {
  328.             status_line[i].color = appres.m3279 ?
  329.                 colors3279[i] : colors[i];
  330.         }
  331.     }
  332.  
  333.     for (i = 0; i < SSZ; i++)
  334.         status_line[i].changed = True;
  335.     status_changed = True;
  336.  
  337.     /*
  338.      * Always redraw all the fields; it's easier than keeping track of
  339.      * what may have changed and why.
  340.      */
  341.     do_ctlr();
  342.     paint_msg(oia_msg);
  343.     do_insert(oia_insert);
  344.     do_reverse(oia_reverse);
  345.     do_kmap(oia_kmap);
  346.     do_script(oia_script);
  347.     do_shift(oia_shift);
  348.     do_typeahead(oia_typeahead);
  349.     do_compose(oia_compose, oia_compose_char, oia_compose_keytype);
  350.     do_cursor(oia_cursor);
  351.     do_timing(oia_timing);
  352. }
  353.  
  354. /* Render the status line onto the screen */
  355. void
  356. status_disp(void)
  357. {
  358.     unsigned i;
  359.  
  360.     if (!status_changed)
  361.         return;
  362.     for (i = 0; i < SSZ; i++)
  363.         if (status_line[i].changed) {
  364.             status_render(i);
  365.             (void) memmove(status_line[i].d2b, status_line[i].s2b,
  366.                    status_line[i].len * sizeof(XChar2b));
  367.             status_line[i].changed = False;
  368.         }
  369.     status_changed = False;
  370. }
  371.  
  372. /* Mark the entire status line as changed */
  373. void
  374. status_touch(void)
  375. {
  376.     unsigned i;
  377.  
  378.     for (i = 0; i < SSZ; i++) {
  379.         status_line[i].changed = True;
  380.         (void) memset(status_line[i].d2b, 0,
  381.             status_line[i].len * sizeof(XChar2b));
  382.     }
  383.     status_changed = True;
  384. }
  385.  
  386. /* Keyboard lock status changed */
  387. void
  388. status_kybdlock(void)
  389. {
  390.     /* presently implemented as explicit calls */
  391. }
  392.  
  393. /* Connected or disconnected */
  394. static void
  395. status_connect(Boolean connected)
  396. {
  397.     if (connected) {
  398.         oia_boxsolid = IN_3270 && !IN_SSCP;
  399.         do_ctlr();
  400.         if (kybdlock & KL_AWAITING_FIRST)
  401.             do_msg(NONSPECIFIC);
  402.         else
  403.             do_msg(BLANK);
  404.         status_untiming();
  405.     } else {
  406.         oia_boxsolid = False;
  407.         do_ctlr();
  408.         do_msg(DISCONNECTED);
  409.         status_uncursor_pos();
  410.     }
  411. }
  412.  
  413. /* Changed 3270 mode */
  414. static void
  415. status_3270_mode(Boolean connected)
  416. {
  417.     oia_boxsolid = IN_3270 && !IN_SSCP;
  418.     do_ctlr();
  419.     status_untiming();
  420. }
  421.  
  422. /* Half connected */
  423. static void
  424. status_half_connect(Boolean ignored unused)
  425. {
  426.     oia_boxsolid = False;
  427.     do_ctlr();
  428.     do_msg(CONNECTING);
  429.     status_untiming();
  430.     status_uncursor_pos();
  431. }
  432.  
  433. /* Lock the keyboard (twait) */
  434. void
  435. status_twait(void)
  436. {
  437.     oia_undera = False;
  438.     do_ctlr();
  439.     do_msg(TWAIT);
  440. }
  441.  
  442. /* Done with controller confirmation */
  443. void
  444. status_ctlr_done(void)
  445. {
  446.     oia_undera = True;
  447.     do_ctlr();
  448. }
  449.  
  450. /* Lock the keyboard (X SYSTEM) */
  451. void
  452. status_syswait(void)
  453. {
  454.     do_msg(SYSWAIT);
  455. }
  456.  
  457. /* Lock the keyboard (operator error) */
  458. void
  459. status_oerr(int error_type)
  460. {
  461.     switch (error_type) {
  462.         case KL_OERR_PROTECTED:
  463.         do_msg(PROTECTED);
  464.         break;
  465.         case KL_OERR_NUMERIC:
  466.         do_msg(NUMERIC);
  467.         break;
  468.         case KL_OERR_OVERFLOW:
  469.         do_msg(OVERFLOW);
  470.         break;
  471.     }
  472. }
  473.  
  474. /* Lock the keyboard (X Scrolled) */
  475. void
  476. status_scrolled(int n)
  477. {
  478.     if (n != 0) {
  479.         if (!msg_is_saved) {
  480.             saved_msg = oia_msg;
  481.             msg_is_saved = True;
  482.         }
  483.         n_scrolled = n;
  484.         paint_msg(SCROLLED);
  485.     } else {
  486.         if (msg_is_saved) {
  487.             msg_is_saved = False;
  488.             paint_msg(saved_msg);
  489.         }
  490.     }
  491. }
  492.  
  493. /* Lock the keyboard (X -f) */
  494. void
  495. status_minus(void)
  496. {
  497.     do_msg(MINUS);
  498. }
  499.  
  500. /* Unlock the keyboard */
  501. void
  502. status_reset(void)
  503. {
  504.     if (kybdlock & KL_ENTER_INHIBIT)
  505.         do_msg(INHIBIT);
  506.     else if (kybdlock & KL_DEFERRED_UNLOCK)
  507.         do_msg(NONSPECIFIC);
  508.     else
  509.         do_msg(BLANK);
  510. }
  511.  
  512. /* Toggle insert mode */
  513. void
  514. status_insert_mode(Boolean on)
  515. {
  516.     do_insert(oia_insert = on);
  517. }
  518.  
  519. /* Toggle reverse mode */
  520. void
  521. status_reverse_mode(Boolean on)
  522. {
  523.     do_reverse(oia_reverse = on);
  524. }
  525.  
  526. /* Toggle kmap mode */
  527. void
  528. status_kmap(Boolean on)
  529. {
  530.     do_kmap(oia_kmap = on);
  531. }
  532.  
  533. /* Toggle script mode */
  534. void
  535. status_script(Boolean on)
  536. {
  537.     do_script(oia_script = on);
  538. }
  539.  
  540. /* Toggle shift mode */
  541. void
  542. status_shift_mode(int state)
  543. {
  544.     do_shift(oia_shift = state);
  545. }
  546.  
  547. /* Toggle typeahead */
  548. void
  549. status_typeahead(Boolean on)
  550. {
  551.     do_typeahead(oia_typeahead = on);
  552. }
  553.  
  554. /* Set compose character */
  555. void
  556. status_compose(Boolean on, unsigned char c, enum keytype keytype)
  557. {
  558.     oia_compose = on;
  559.     oia_compose_char = c;
  560.     oia_compose_keytype = keytype;
  561.     do_compose(on, c, keytype);
  562. }
  563.  
  564. /* Display timing */
  565. void
  566. status_timing(struct timeval *t0, struct timeval *t1)
  567. {
  568.     static char    no_time[] = ":??.?";
  569.     static char    buf[TCNT+1];
  570.  
  571.     if (t1->tv_sec - t0->tv_sec > (99*60)) {
  572.         do_timing(oia_timing = no_time);
  573.     } else {
  574.         unsigned long cs;    /* centiseconds */
  575.  
  576.         cs = (t1->tv_sec - t0->tv_sec) * 10 +
  577.              (t1->tv_usec - t0->tv_usec + 50000) / 100000;
  578.         if (cs < CM)
  579.             (void) sprintf(buf, ":%02ld.%ld", cs / 10, cs % 10);
  580.         else
  581.             (void) sprintf(buf, "%02ld:%02ld", cs / CM, (cs % CM) / 10);
  582.         do_timing(oia_timing = buf);
  583.     }
  584. }
  585.  
  586. /* Erase timing indication */
  587. void
  588. status_untiming(void)
  589. {
  590.     do_timing(oia_timing = (char *) 0);
  591. }
  592.  
  593. /* Update cursor position */
  594. void
  595. status_cursor_pos(int ca)
  596. {
  597.     static char    buf[CCNT+1];
  598.  
  599.     (void) sprintf(buf, "%03d/%03d", ca/COLS + 1, ca%COLS + 1);
  600.     do_cursor(oia_cursor = buf);
  601. }
  602.  
  603. /* Erase cursor position */
  604. void
  605. status_uncursor_pos(void)
  606. {
  607.     do_cursor(oia_cursor = (char *) 0);
  608. }
  609.  
  610.  
  611. /* Internal routines */
  612.  
  613. /* Update the status line by displaying "symbol" at column "col".  */
  614. static void
  615. status_add(int col, unsigned char symbol, enum keytype keytype)
  616. {
  617.     unsigned i;
  618.     XChar2b n2b;
  619.  
  620.     n2b.byte1 = (keytype == KT_STD) ? 0 : 1;
  621.     n2b.byte2 = symbol;
  622.     if (status_2b[col].byte1 == n2b.byte1 &&
  623.         status_2b[col].byte2 == n2b.byte2)
  624.         return;
  625.     status_2b[col] = n2b;
  626.     status_1b[col] = symbol;
  627.     status_changed = True;
  628.     for (i = 0; i < SSZ; i++)
  629.         if (col >= status_line[i].start &&
  630.             col <  status_line[i].start + status_line[i].len) {
  631.             status_line[i].changed = True;
  632.             return;
  633.         }
  634. }
  635.  
  636. /*
  637.  * Render a region of the status line onto the display, the idea being to
  638.  * minimize the number of redundant X drawing operations performed.
  639.  *
  640.  * What isn't optimized is what happens when "ABC" becomes "XBZ" -- should we
  641.  * redundantly draw over B or not?  Right now we don't.
  642.  */
  643. static void
  644. status_render(int region)
  645. {
  646.     int    i;
  647.     struct status_line *sl = &status_line[region];
  648.     int    nd = 0;
  649.     int    i0 = -1;
  650.  
  651.     /* The status region may change colors; don't be so clever */
  652.     if (region == WAIT_REGION) {
  653.         XDrawImageString(display, *screen_window, screen_gc(sl->color),
  654.             COL_TO_X(sl->start), status_y, (char *) sl->s1b, sl->len);
  655.     } else {
  656.         for (i = 0; i < sl->len; i++) {
  657.             if (sl->s2b[i].byte1 == sl->d2b[i].byte1 &&
  658.                 sl->s2b[i].byte2 == sl->d2b[i].byte2) {
  659.                 if (nd) {
  660.                     if (*extended_3270font)
  661.                         XDrawImageString16(display,
  662.                             *screen_window,
  663.                             screen_gc(sl->color),
  664.                             COL_TO_X(sl->start + i0),
  665.                             status_y,
  666.                             sl->s2b + i0, nd);
  667.                     else
  668.                         XDrawImageString(display,
  669.                             *screen_window,
  670.                             screen_gc(sl->color),
  671.                             COL_TO_X(sl->start + i0),
  672.                             status_y,
  673.                             (char *) sl->s1b + i0, nd);
  674.                     nd = 0;
  675.                     i0 = -1;
  676.                 }
  677.             } else {
  678.                 if (!nd++)
  679.                     i0 = i;
  680.             }
  681.         }
  682.         if (nd) {
  683.             if (*extended_3270font)
  684.                 XDrawImageString16(display, *screen_window,
  685.                     screen_gc(sl->color),
  686.                     COL_TO_X(sl->start + i0), status_y,
  687.                     sl->s2b + i0, nd);
  688.             else
  689.                 XDrawImageString(display, *screen_window,
  690.                     screen_gc(sl->color),
  691.                     COL_TO_X(sl->start + i0), status_y,
  692.                     (char *)sl->s1b + i0, nd);
  693.         }
  694.     }
  695.  
  696.     /* Leftmost region has unusual attributes */
  697.     if (*standard_font && region == CTLR_REGION) {
  698.         XDrawImageString(display, *screen_window,
  699.             screen_invgc(sl->color),
  700.             COL_TO_X(sl->start + LBOX), status_y,
  701.             (char *) sl->s1b + LBOX, 1);
  702.         XDrawRectangle(display, *screen_window, screen_gc(sl->color),
  703.             COL_TO_X(sl->start + CNCT),
  704.             status_y - *ascent + *char_height - 1,
  705.             *char_width - 1, 0);
  706.         XDrawImageString(display, *screen_window,
  707.             screen_invgc(sl->color),
  708.             COL_TO_X(sl->start + RBOX), status_y,
  709.             (char *) sl->s1b + RBOX, 1);
  710.     }
  711. }
  712.  
  713. /* Write into the message area of the status line */
  714. static void
  715. status_msg_set(unsigned const char *msg, int len)
  716. {
  717.     register int    i;
  718.  
  719.     for (i = 0; i < status_line[WAIT_REGION].len; i++) {
  720.         status_add(M0+i, len ? msg[i] : nullblank, KT_STD);
  721.         if (len)
  722.             len--;
  723.     }
  724. }
  725.  
  726. /* Controller status */
  727. static void
  728. do_ctlr(void)
  729. {
  730.     if (*standard_font) {
  731.         status_add(LBOX, '4', KT_STD);
  732.         if (oia_undera)
  733.             status_add(CNCT, (IN_E ? 'B' : 'A'), KT_STD);
  734.         else
  735.             status_add(CNCT, ' ', KT_STD);
  736.         if (IN_ANSI)
  737.             status_add(RBOX, 'N', KT_STD);
  738.         else if (oia_boxsolid)
  739.             status_add(RBOX, ' ', KT_STD);
  740.         else if (IN_SSCP)
  741.             status_add(RBOX, 'S', KT_STD);
  742.         else
  743.             status_add(RBOX, '?', KT_STD);
  744.     } else {
  745.         status_add(LBOX, CG_box4, KT_STD);
  746.         if (oia_undera)
  747.             status_add(CNCT, (IN_E ? CG_underB : CG_underA),
  748.                 KT_STD);
  749.         else
  750.             status_add(CNCT, CG_null, KT_STD);
  751.         if (IN_ANSI)
  752.             status_add(RBOX, CG_N, KT_STD);
  753.         else if (oia_boxsolid)
  754.             status_add(RBOX, CG_boxsolid, KT_STD);
  755.         else if (IN_SSCP)
  756.             status_add(RBOX, CG_boxhuman, KT_STD);
  757.         else
  758.             status_add(RBOX, CG_boxquestion, KT_STD);
  759.     }
  760. }
  761.  
  762. /* Message area */
  763.  
  764. /* Change the state of the message area, or if scrolled, the saved message */
  765. static void
  766. do_msg(enum msg t)
  767. {
  768.     if (msg_is_saved) {
  769.         saved_msg = t;
  770.         return;
  771.     }
  772.     paint_msg(t);
  773. }
  774.  
  775. /* Paint the message area. */
  776. static void
  777. paint_msg(enum msg t)
  778. {
  779.     oia_msg = t;
  780.     (*msg_proc[(int)t])();
  781.     if (!appres.mono)
  782.         status_line[WAIT_REGION].color = appres.m3279 ?
  783.             msg_color3279[(int)t] : msg_color[(int)t];
  784. }
  785.  
  786. static void
  787. do_blank(void)
  788. {
  789.     status_msg_set((unsigned char *) 0, 0);
  790. }
  791.  
  792. static void
  793. do_disconnected(void)
  794. {
  795.     if (*standard_font)
  796.         status_msg_set(a_not_connected,
  797.             strlen((char *)a_not_connected));
  798.     else
  799.         status_msg_set(disc_msg, disc_len);
  800. }
  801.  
  802. static void
  803. do_connecting(void)
  804. {
  805.     if (*standard_font)
  806.         status_msg_set(a_connecting, strlen((char *)a_connecting));
  807.     else
  808.         status_msg_set(cnct_msg, cnct_len);
  809. }
  810.  
  811. static void
  812. do_nonspecific(void)
  813. {
  814.     static unsigned char nonspecific[] = {
  815.         CG_lock
  816.     };
  817.  
  818.     if (*standard_font)
  819.         status_msg_set((unsigned const char *)"X", 1);
  820.     else
  821.         status_msg_set(nonspecific, sizeof(nonspecific));
  822. }
  823.  
  824. static void
  825. do_inhibit(void)
  826. {
  827.     static unsigned char inhibit[] = {
  828.         CG_lock, CG_space, CG_I, CG_n, CG_h, CG_i, CG_b, CG_i, CG_t
  829.     };
  830.  
  831.     if (*standard_font)
  832.         status_msg_set(a_inhibit, strlen((char *)a_inhibit));
  833.     else
  834.         status_msg_set(inhibit, sizeof(inhibit));
  835. }
  836.  
  837. static void
  838. do_twait(void)
  839. {
  840.     static unsigned char twait[] = {
  841.         CG_lock, CG_space, CG_clockleft, CG_clockright
  842.     };
  843.  
  844.     if (*standard_font)
  845.         status_msg_set(a_twait, strlen((char *)a_twait));
  846.     else
  847.         status_msg_set(twait, sizeof(twait));
  848. }
  849.  
  850. static void
  851. do_syswait(void)
  852. {
  853.     static unsigned char syswait[] = {
  854.         CG_lock, CG_space, CG_S, CG_Y, CG_S, CG_T, CG_E, CG_M
  855.     };
  856.  
  857.     if (*standard_font)
  858.         status_msg_set(a_syswait, strlen((char *)a_syswait));
  859.     else
  860.         status_msg_set(syswait, sizeof(syswait));
  861. }
  862.  
  863. static void
  864. do_protected(void)
  865. {
  866.     static unsigned char protected[] = {
  867.         CG_lock, CG_space, CG_leftarrow, CG_human, CG_rightarrow
  868.     };
  869.  
  870.     if (*standard_font)
  871.         status_msg_set(a_protected, strlen((char *)a_protected));
  872.     else
  873.         status_msg_set(protected, sizeof(protected));
  874. }
  875.  
  876. static void
  877. do_numeric(void)
  878. {
  879.     static unsigned char numeric[] = {
  880.         CG_lock, CG_space, CG_human, CG_N, CG_U, CG_M
  881.     };
  882.  
  883.     if (*standard_font)
  884.         status_msg_set(a_numeric, strlen((char *)a_numeric));
  885.     else
  886.         status_msg_set(numeric, sizeof(numeric));
  887. }
  888.  
  889. static void
  890. do_overflow(void)
  891. {
  892.     static unsigned char overflow[] = {
  893.         CG_lock, CG_space, CG_human, CG_greater
  894.     };
  895.  
  896.     if (*standard_font)
  897.         status_msg_set(a_overflow, strlen((char *)a_overflow));
  898.     else
  899.         status_msg_set(overflow, sizeof(overflow));
  900. }
  901.  
  902. static void
  903. do_scrolled(void)
  904. {
  905.     static unsigned char scrolled[] = {
  906.         CG_lock, CG_space, CG_S, CG_c, CG_r, CG_o, CG_l, CG_l, CG_e,
  907.         CG_d, CG_space, CG_space, CG_space, CG_space, CG_space
  908.     };
  909.     static unsigned char spaces[] = {
  910.         CG_space, CG_space, CG_space, CG_space
  911.     };
  912.  
  913.     if (*standard_font) {
  914.         char *t;
  915.  
  916.         t = XtMalloc(strlen((char *)a_scrolled) + 4);
  917.         (void) sprintf(t, "%s %d", (char *)a_scrolled, n_scrolled);
  918.         status_msg_set((unsigned char *)t, strlen(t));
  919.         XtFree(t);
  920.     } else {
  921.         char nnn[5];
  922.         int i;
  923.  
  924.         (void) sprintf(nnn, "%d", n_scrolled);
  925.         (void) memcpy((char *)&scrolled[11], (char *)spaces,
  926.             sizeof(spaces));
  927.         for (i = 0; nnn[i]; i++)
  928.             scrolled[11 + i] = asc2cg[(int)nnn[i]];
  929.         status_msg_set(scrolled, sizeof(scrolled));
  930.     }
  931. }
  932.  
  933. static void
  934. do_minus(void)
  935. {
  936.     static unsigned char minus[] = {
  937.         CG_lock, CG_space, CG_minus, CG_f
  938.     };
  939.  
  940.     if (*standard_font)
  941.         status_msg_set(a_minus, strlen((char *)a_minus));
  942.     else
  943.         status_msg_set(minus, sizeof(minus));
  944. }
  945.  
  946. /* Insert, reverse, kmap, script, shift, compose */
  947.  
  948. static void
  949. do_insert(Boolean on)
  950. {
  951.     status_add(INSERT, on ? (*standard_font ? 'I' : CG_insert) : nullblank, KT_STD);
  952. }
  953.  
  954. static void
  955. do_reverse(Boolean on)
  956. {
  957.     status_add(REVERSE, on ? (*standard_font ? 'R' : CG_R) : nullblank, KT_STD);
  958. }
  959.  
  960. static void
  961. do_kmap(Boolean on)
  962. {
  963.     status_add(KMAP, on ? (*standard_font ? 'K' : CG_K) : nullblank, KT_STD);
  964. }
  965.  
  966. static void
  967. do_script(Boolean on)
  968. {
  969.     status_add(SCRIPT, on ? (*standard_font ? 'S' : CG_S) : nullblank, KT_STD);
  970. }
  971.  
  972. static void
  973. do_shift(int state)
  974. {
  975.     status_add(SHIFT-2, (state & MetaKeyDown) ?
  976.         (*standard_font ? 'M' : CG_M) : nullblank, KT_STD);
  977.     status_add(SHIFT-1, (state & AltKeyDown) ?
  978.         (*standard_font ? 'A' : CG_A) : nullblank, KT_STD);
  979.     status_add(SHIFT, (state & ShiftKeyDown) ?
  980.         (*standard_font ? '^' : CG_upshift) : nullblank, KT_STD);
  981. }
  982.  
  983. static void
  984. do_typeahead(int state)
  985. {
  986.     status_add(TYPEAHD, state ? (*standard_font ? 'T' : CG_T) : nullblank, KT_STD);
  987. }
  988.  
  989. static void
  990. do_compose(Boolean on, unsigned char c, enum keytype keytype)
  991. {
  992.     if (on) {
  993.         status_add(COMPOSE,
  994.             (unsigned char)(*standard_font ? 'C' : CG_C), KT_STD);
  995.         status_add(COMPOSE+1,
  996.             c ? (*standard_font ? c : asc2cg[c]) : nullblank, keytype);
  997.     } else {
  998.         status_add(COMPOSE, nullblank, KT_STD);
  999.         status_add(COMPOSE+1, nullblank, KT_STD);
  1000.     }
  1001. }
  1002.  
  1003. /* Timing */
  1004. static void
  1005. do_timing(char *buf)
  1006. {
  1007.     register int    i;
  1008.  
  1009.     if (buf) {
  1010.         if (*standard_font) {
  1011.             status_add(T0, nullblank, KT_STD);
  1012.             status_add(T0+1, nullblank, KT_STD);
  1013.         } else {
  1014.             status_add(T0, CG_clockleft, KT_STD);
  1015.             status_add(T0+1, CG_clockright, KT_STD);
  1016.         }
  1017.         for (i = 0; i < (int) strlen(buf); i++)
  1018.             status_add(T0+2+i, *standard_font ? buf[i] : asc2cg[(unsigned char) buf[i]], KT_STD);
  1019.     } else
  1020.         for (i = 0; i < TCNT; i++)
  1021.             status_add(T0+i, nullblank, KT_STD);
  1022. }
  1023.  
  1024. /* Cursor position */
  1025. static void
  1026. do_cursor(char *buf)
  1027. {
  1028.     register int    i;
  1029.  
  1030.     if (buf)
  1031.         for (i = 0; i < (int) strlen(buf); i++)
  1032.             status_add(C0+i, *standard_font ? buf[i] : asc2cg[(unsigned char) buf[i]], KT_STD);
  1033.     else
  1034.         for (i = 0; i < CCNT; i++)
  1035.             status_add(C0+i, nullblank, KT_STD);
  1036. }
  1037.  
  1038. /* Prepare status messages */
  1039.  
  1040. static unsigned char *
  1041. make_amsg(const char *key)
  1042. {
  1043.     return (unsigned char *)xs_buffer("X %s", get_message(key));
  1044. }
  1045.  
  1046. static unsigned char *
  1047. make_emsg(unsigned char prefix[], const char *key, int *len)
  1048. {
  1049.     const char *text = get_message(key);
  1050.     unsigned char *buf = (unsigned char *)XtMalloc(*len + strlen(text));
  1051.  
  1052.     (void) memmove(buf, prefix, *len);
  1053.     while (*text)
  1054.         buf[(*len)++] = asc2cg[(int)*text++];
  1055.  
  1056.     return buf;
  1057. }
  1058.